package com.ityu.common.utils;

import org.bouncycastle.util.encoders.Hex;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ExecutionException;

public class EthUtils {
    public final static String MAIN_URL = "https://mainnet.infura.io/v3/2ef8c4b6a8e54cc4b28e3b3b9da2780b";
    public final static String KOVAN_URL = "https://kovan.infura.io/v3/2ef8c4b6a8e54cc4b28e3b3b9da2780b";


    public static EthSendTransaction sendCustomETH(Credentials credentials, String toaddress, String count, int isTest) throws Exception {
        // get the next available nonce
        EthGetTransactionCount ethGetTransactionCount = getWeb3j(isTest).ethGetTransactionCount(
                credentials.getAddress(), DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        BigInteger price = getWeb3j(isTest).ethGasPrice().send().getGasPrice();
        RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
                nonce, price, Transfer.GAS_LIMIT, toaddress, Convert.toWei(count, Convert.Unit.ETHER).toBigInteger());
        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
        String hexValue = "0x" + Hex.toHexString(signedMessage);
        return getWeb3j(isTest).ethSendRawTransaction(hexValue).send();
    }

    /**
     * 发送方地址
     *
     * @param amount      接收者地址
     * @param to          发送方私钥
     * @param coinAddress

     * @throws InterruptedException
     */
    public static String signTokenTransaction(Credentials credentials, String to,String amount, String coinAddress, int decimals, int isTest)
            throws IOException, ExecutionException, InterruptedException {

        EthGetTransactionCount ethGetTransactionCount = getWeb3j(isTest).ethGetTransactionCount(
                credentials.getAddress(), DefaultBlockParameterName.LATEST).sendAsync().get();

        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        //支付的矿工费
        BigInteger gasPrice = getWeb3j(isTest).ethGasPrice().send().getGasPrice().multiply(new BigInteger("10"));
        BigInteger gasLimit = new BigInteger("90000");
        BigInteger amountWei = BigDecimal.TEN.pow(decimals).multiply(new BigDecimal(amount)).toBigInteger();
        //封装转账交易
        Function function = new Function(
                "transfer",
                Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(to),
                        new org.web3j.abi.datatypes.generated.Uint256(amountWei)),
                Collections.<TypeReference<?>>emptyList());
        String data = FunctionEncoder.encode(function);
        //签名交易
        RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice.multiply(new BigInteger("12")).divide(BigInteger.TEN), gasLimit, coinAddress, data);
        byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);

        //广播交易
        String hash = getWeb3j(isTest).ethSendRawTransaction(Numeric.toHexString(signMessage)).sendAsync().get().getTransactionHash();
        return hash;
    }


    /**
     * 通过私钥获取凭证
     *
     * @param privateKey
     * @return
     */
    public static Credentials getCreFromPrivateKey(String privateKey) {
        return Credentials.create(privateKey);
    }

    public static Web3j getWeb3j(int isTest) {
        return Web3j.build(new HttpService(isTest == 0 ? MAIN_URL : KOVAN_URL));
    }

    public static void main(String[] args) {
        Credentials creFromPrivateKey = EthUtils.getCreFromPrivateKey("b05d79f5f9605a2f8156475856677fa5feef8d1c6a4105842984e4a60955e6df");
        String sendCustomETH = null;
        try {
            sendCustomETH = EthUtils.sendCustomETH(creFromPrivateKey, "0x1742525e081385C24F793319166DddFdB9602BE9", "0.5", 1).getTransactionHash();
            System.out.println(sendCustomETH);

            String signTokenTransaction = EthUtils.signTokenTransaction(creFromPrivateKey, "0x1742525e081385C24F793319166DddFdB9602BE9", "2", "0xb88b8785f87596428026357e0646d3f2fc6e4ba2", 6, 1 );
            System.out.println(signTokenTransaction);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
